﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using QW.Core.IOC;
using Microsoft.Extensions.DependencyInjection.Extensions;

namespace QW.Found.Extensions
{
    /// <summary>
    /// 注入扩展
    /// <para>感谢Furion框架，本功能大量参考了Furion的注入方式</para>
    /// </summary>
    public static class DependencyInjectionExtensions
    {
        /// <summary>
        /// 注入业务依赖
        /// </summary>
        /// <param name="services"></param>
        /// <param name="assemblies"></param>
        public static void AddDependencyInjection(this IServiceCollection services, List<Assembly> assemblies)
        {
            assemblies = assemblies
               .Where(lib => lib.GetTypes().Any(d => typeof(IDependency).IsAssignableFrom(d)))
               .ToList();

            foreach (var item in assemblies)
            {
                var types = item.GetTypes()
                    .Where(p => !p.IsInterface && !p.IsAbstract && !p.IsSealed)
                    .Where(p => typeof(IDependency).IsAssignableFrom(p))
                    .ToList();

                foreach (var type in types)
                {
                    //注入泛型的方式
                    //services.AddTransient(typeof(IBaseRepository<,>), typeof(BaseRepository<,>));

                    //获取注入的生命周期
                    var _slt = GetServiceLifetime(type);

                    Dictionary<Type, Type> iocdic = new Dictionary<Type, Type>();
                    //默认注入自身
                    iocdic.Add(type, type);

                    if (typeof(IImplementAsInterfaces).IsAssignableFrom(type))
                    {
                        //按接口注入
                        iocdic.Clear();

                        var _sql = type.GetInterfaces().Where(p => p != typeof(IDisposable) && p != typeof(IAsyncDisposable));
                        //排除IOC定义接口
                        _sql = _sql.Where(p => !(!string.IsNullOrWhiteSpace(p.FullName) && p.FullName.StartsWith("QW.Core.IOC")));

                        //获取所有能注入的接口
                        _sql = _sql.Where(p => ((!type.IsGenericType && !p.IsGenericType)
                                || (type.IsGenericType && p.IsGenericType && type.GetGenericArguments().Length == p.GetGenericArguments().Length))
                            );

                        var _interfaces = _sql.ToList();
                        foreach (var _in in _interfaces)
                        {
                            if (_in == null) { continue; }
                            //泛型接口处理
                            iocdic.Add(_in, type);
                        }
                    }

                    foreach (var _dic in iocdic)
                    {
                        Register(services, _dic.Key, _dic.Value, _slt);
                    }
                }
            }
        }
        /// <summary>
        /// 注册类型
        /// </summary>
        /// <param name="services">服务</param>
        /// <param name="inter">定义类型</param>
        /// <param name="type">实现类型</param>
        /// <param name="lifetime">生命周期</param>
        private static void Register(IServiceCollection services, Type inter, Type type, ServiceLifetime lifetime)
        {
            // 修复泛型注册类型
            var fixedType = FixedGenericType(type);
            var fixedInter = inter == null ? null : FixedGenericType(inter);

            if (fixedInter == null)
            {
                services.TryAdd(ServiceDescriptor.Describe(fixedType, fixedType, lifetime));
            }
            else
            {
                services.Add(ServiceDescriptor.Describe(fixedInter, fixedType, lifetime));
            }
        }
        /// <summary>
        /// 修复泛型类型注册类型
        /// </summary>
        /// <param name="type">类型</param>
        /// <returns></returns>
        private static Type FixedGenericType(Type type)
        {
            if (!type.IsGenericType) return type;

            return type.Assembly.GetType($"{type.Namespace}.{type.Name}");
        }
        /// <summary>
        /// 获取类型注入的生命周期
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private static ServiceLifetime GetServiceLifetime(Type type)
        {
            //默认 瞬态
            var result = ServiceLifetime.Transient;
            if (typeof(ISingletonDependency).IsAssignableFrom(type))
            {
                //单例
                result = ServiceLifetime.Singleton;
            }
            else if (typeof(IScopedDependency).IsAssignableFrom(type))
            {
                //范围
                result = ServiceLifetime.Scoped;
            }
            return result;
        }
    }
}
